package util;

import java.io.Serializable;
import java.util.Map;
import java.util.List;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 
 * @author Danon
 */
public class DirectedGraph<Router, Link> implements Serializable {
    public final long serialVersionID = 1L;
    
    private final Map<Router, List<Pair<Router, Link>>> vertices;

    public DirectedGraph() {
        vertices = new ConcurrentHashMap<Router, List<Pair<Router, Link>>>();
    }
    
    public DirectedGraph(DirectedGraph<Router, Link> g) {
        this();
        Set<Router> v = g.getVertices();
        for(Router r : v) {
            addVertexIfNotExists(r);
            getIncidentVertices(r).addAll(g.getIncidentVertices(r));
        }
    }
    
    public synchronized List<Pair<Router, Link>> addVertex(Router r) {
        return vertices.put(r, Collections.synchronizedList(new LinkedList<Pair<Router, Link>>()));
    }
    
    public synchronized final boolean addVertexIfNotExists(Router r) {
        if(vertices.get(r)==null) {
            addVertex(r);
            return true;
        }
        return false;
    }
    
    public synchronized final Set<Router> getVertices() {
        return vertices.keySet();
    }
    
    public synchronized final List<Pair<Router, Link>> getIncidentVertices(Router r) {
        return vertices.get(r);
    }
    
    public synchronized Link getEdge(Router v1, Router v2) {
        List<Pair<Router, Link>> edges = vertices.get(v1);
        if(edges==null) return null;
        for(Pair<Router, Link> pair : edges)
            if(pair.getA().equals(v2))
                return pair.getB();
        return null;
    }
    
    public synchronized final boolean hasEdge(Router v1, Router v2) {
        return getEdge(v1, v2) != null;
    }
    
    public synchronized void clear() {
        Set<Map.Entry<Router, List<Pair<Router, Link>>>> s = vertices.entrySet();
        for(Map.Entry<Router, List<Pair<Router, Link>>> e : s)
            if(e.getValue()!=null) e.getValue().clear();
        vertices.clear();
            
    }
    
    public synchronized void addEdge(Router v1, Router v2, Link l) {
        addVertexIfNotExists(v1);
        addVertexIfNotExists(v2);
        vertices.get(v1).add(new Pair<Router, Link>(v2, l));
        //vertices.get(v2).add(new Pair<Router, Link>(v1, l));
    }
    
    public synchronized void removeEdge(Router v1, Router v2, Link l) {
        vertices.get(v1).remove(new Pair<Router, Link>(v2, l));
        vertices.get(v2).remove(new Pair<Router, Link>(v1, l));
    }
    
    
}
